package cn.xydpeng.springframework.beans;

import cn.xydpeng.springframework.util.Assert;
import cn.xydpeng.springframework.util.ReflectionUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xydpeng
 * @version v1.0
 * @date: 2022/10/12
 * @description:
 */
public abstract class BeanUtils {

    private static final Map<Class<?>, Object> DEFAULT_TYPE_VALUES = new HashMap<>(8);

    static {
        DEFAULT_TYPE_VALUES.put(boolean.class, false);
        DEFAULT_TYPE_VALUES.put(byte.class, (byte) 0);
        DEFAULT_TYPE_VALUES.put(short.class, (short) 0);
        DEFAULT_TYPE_VALUES.put(int.class, 0);
        DEFAULT_TYPE_VALUES.put(long.class, 0L);
        DEFAULT_TYPE_VALUES.put(float.class, 0F);
        DEFAULT_TYPE_VALUES.put(double.class, 0D);
        DEFAULT_TYPE_VALUES.put(char.class, '\0');
    }


    public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeansException {
        try {
            ReflectionUtils.makeAccessible(ctor);
            Class<?>[] parameterTypes = ctor.getParameterTypes();
            Assert.isTrue(args.length <= parameterTypes.length, "args num error");

            Object[] argsWithDefaultValues = new Object[args.length];
            for (int i = 0; i < args.length; i++) {
                if (args[i] == null) {
                    Class<?> parameterType = parameterTypes[i];
                    argsWithDefaultValues[i] = parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null;
                } else {
                    argsWithDefaultValues[i] = args[i];
                }
            }
            return ctor.newInstance(argsWithDefaultValues);
        } catch (Exception e) {
            throw new BeansException("instantiateClass error", e);
        }
    }

    public static void setFieldValue(Object target,String FieldName,Object value){
        Class<?> clazz = target.getClass();
        Field field = ReflectionUtils.findField(clazz, FieldName);
        ReflectionUtils.makeAccessible(field);
        ReflectionUtils.setField(field,target,value);
    }


}
